package com.wingscode.modules.app.controller;

import com.alibaba.fastjson.JSONObject;
import com.wingscode.common.utils.IPUtils;
import com.wingscode.common.utils.PayUtil;
import com.wingscode.common.utils.UUIDHexGenerator;
import com.wingscode.common.utils.XmlUtil;
import com.wingscode.modules.app.form.OrderForm;
import com.wingscode.modules.app.form.PaymentForm;
import com.wingscode.modules.common.entity.AddedSettingEntity;
import com.wingscode.modules.common.entity.UserEntity;
import com.wingscode.modules.common.entity.UserOrderEntity;
import com.wingscode.modules.common.service.AddedSettingService;
import com.wingscode.modules.common.service.UserOrderService;
import com.wingscode.modules.common.service.UserService;
import com.wingscode.modules.sys.controller.AbstractController;
import io.swagger.annotations.Api;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.wingscode.MyConfig.MINI_APPID;

/**
 * 增值服务
 *
 * @author yan
 */
@RestController
@RequestMapping("/wx")
@Api("增值服务")
public class PayController extends AbstractController {
    private final String mch_id = "填写商户号";//商户号
    private final String notify_url = "域名/wx/payCallback";//通知地址
    private final String trade_type = "JSAPI";//交易类型
    private final String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单API接口链接
    private final String key = "&key=填写商户支付密钥"; // 商户支付密钥

    @Autowired
    private UserOrderService userOrderService;
    @Autowired
    private UserService userService;
    @Autowired
    private AddedSettingService addedSettingService;

    /**
     *
     * @param orderForm
     * @return
     * @throws UnsupportedEncodingException
     * @throws DocumentException
     */
    @PostMapping("/payment")
    @ResponseBody
    public JSONObject payment(@RequestBody OrderForm orderForm, HttpServletRequest request) throws UnsupportedEncodingException, DocumentException {
        JSONObject JsonObject = new JSONObject();
        String attach = "";

        if (orderForm.getOrderId() != null) {
            UserOrderEntity orderEntity = userOrderService.getById(orderForm.getOrderId());
            if (orderEntity != null) {
                // 订单已存在的情况
                if (orderEntity.getState() > 0) {
                    JsonObject.put("code", 500);
                    JsonObject.put("msg", "订单已支付");

                    return JsonObject;
                } else {
                    orderEntity.setState(0);
                    orderEntity.setUpdateTime(new Date());

                    userOrderService.updateById(orderEntity);
                }
            } else {
                // 订单不存在，新建待支付订单
                UserEntity user = userService.getById(orderForm.getUserId());
                AddedSettingEntity addedSetting = addedSettingService.getById(orderForm.getAddedSettingId());

                orderEntity.setNumber(UUID.randomUUID().toString().replace("-", ""));
                orderEntity.setUserId(orderForm.getUserId());
                orderEntity.setAgentId(user.getAgentId());
                orderEntity.setPrice(orderForm.getPrice());
                orderEntity.setContent("信息发布");
                orderEntity.setCreateTime(new Date());
                orderEntity.setUpdateTime(new Date());
                orderEntity.setState(0);
                orderEntity.setServiceId(addedSetting.getServiceId());
                orderEntity.setAddedSettingId(orderForm.getAddedSettingId());
                orderEntity.setSource(0);
                orderEntity.setType(0);

                userOrderService.save(orderEntity);
            }

            attach = orderEntity.getId().toString();
        }

        // 订单总金额（分）
        String totalFee = orderForm.getPrice().multiply(BigDecimal.valueOf(100)).toString();
        String body = "人才壹佰";
        body = new String(body.getBytes("UTF-8"),"ISO-8859-1");
        String nonce_str = UUIDHexGenerator.generate();//随机字符串
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String code = PayUtil.createCode(8);
        String out_trade_no = mch_id + today + code;//商户订单号

        String openid = orderForm.getOpenId();//用户标识
        PaymentForm paymentForm = new PaymentForm();
        paymentForm.setAppid(MINI_APPID);
        paymentForm.setMch_id(mch_id);
        paymentForm.setNonce_str(nonce_str);
        // 以utf-8编码放入paymentForm，微信支付要求字符编码统一采用UTF-8字符编码
        String newbody = new String(body.getBytes("ISO-8859-1"),"UTF-8");
        paymentForm.setBody(newbody);
        paymentForm.setOut_trade_no(out_trade_no);
        paymentForm.setTotal_fee(totalFee);
        paymentForm.setSpbill_create_ip(getLocalIp());
        paymentForm.setNotify_url(notify_url);
        paymentForm.setTrade_type(trade_type);
        paymentForm.setOpenid(openid);
        paymentForm.setAttach(attach);
        // 把请求参数打包成数组
        Map<String, Object> sParaTemp = new HashMap();
        sParaTemp.put("appid", paymentForm.getAppid());
        sParaTemp.put("mch_id", paymentForm.getMch_id());
        sParaTemp.put("nonce_str", paymentForm.getNonce_str());
        sParaTemp.put("body", paymentForm.getBody());
        sParaTemp.put("out_trade_no", paymentForm.getOut_trade_no());
        sParaTemp.put("total_fee",paymentForm.getTotal_fee());
        sParaTemp.put("spbill_create_ip", paymentForm.getSpbill_create_ip());
        sParaTemp.put("notify_url",paymentForm.getNotify_url());
        sParaTemp.put("trade_type", paymentForm.getTrade_type());
        sParaTemp.put("openid", paymentForm.getOpenid());
        sParaTemp.put("attach", paymentForm.getAttach());
        // 除去数组中的空值和签名参数
        Map sPara = PayUtil.paraFilter(sParaTemp);
        String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

        //MD5运算生成签名
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        paymentForm.setSign(mysign);
        //打包要发送的xml
        String respXml = XmlUtil.messageToXML(paymentForm);
        // 打印respXml发现，得到的xml中有“__”不对，应该替换成“_”
        respXml = respXml.replace("__", "_");
        String param = respXml;
        String result = PayUtil.httpRequest(url, "POST", param);
        System.out.println("请求微信预支付接口，返回 result："+result);
        // 将解析结果存储在Map中
        Map map = new HashMap();
        InputStream in=new ByteArrayInputStream(result.getBytes());
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(in);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();
        for (Element element : elementList) {
            map.put(element.getName(), element.getText());
        }
        // 返回信息
        String return_code = map.get("return_code").toString();//返回状态码
        String return_msg = map.get("return_msg").toString();//返回信息
        String result_code = map.get("result_code").toString();//返回状态码

        System.out.println("请求微信预支付接口，返回 code：" + return_code);
        System.out.println("请求微信预支付接口，返回 msg：" + return_msg);
        if("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)){
            // 业务结果
            String prepay_id = map.get("prepay_id").toString();//返回的预付单信息
            String nonceStr = UUIDHexGenerator.generate();
            JsonObject.put("nonceStr", nonceStr);
            JsonObject.put("package", "prepay_id=" + prepay_id);
            Long timeStamp = System.currentTimeMillis() / 1000;
            JsonObject.put("timeStamp", timeStamp + "");
            String stringSignTemp = "appId=" + MINI_APPID + "&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;
            //再次签名
            String paySign = PayUtil.sign(stringSignTemp, key, "utf-8").toUpperCase();
            JsonObject.put("paySign", paySign);
        }
        return JsonObject;
    }


    /**
     * 预支付时填写的 notify_url ，支付成功后的回调接口
     * @param request
     */
    @PostMapping("/payCallback")
    @ResponseBody
    public void paycallback(HttpServletRequest request, HttpServletResponse response) {
        try {
            String resXml = "";
            Map<String, Object> dataMap = XmlUtil.parseXML(request);
            String returnCode = (String) dataMap.get("return_code");
            if ("SUCCESS".equalsIgnoreCase(returnCode)) {
                String returnMsg = (String) dataMap.get("result_code");
                if ("SUCCESS".equalsIgnoreCase(returnMsg)) {
                    // 更新订单状态
                    Integer orderId = Integer.parseInt(dataMap.get("attach").toString());
                    UserOrderEntity orderEntity = userOrderService.getById(orderId);
                    if (orderEntity != null) {
                        orderEntity.setState(1);
                        orderEntity.setUpdateTime(new Date());

                        userOrderService.updateById(orderEntity);
                    }

                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg" + "</xml>";
                } else {
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[报文为空]]></return_msg" + "</xml>";
                }
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg" + "</xml>";
            }

            response.getWriter().println(resXml);
            //{"transaction_id":"4200000109201805293331420304","nonce_str":"402880e963a9764b0163a979a16e0002","bank_type":"CFT","openid":"oXI6G5Jc4D44y2wixgxE3OPwpDVg","sign":"262978D36A3093ACBE4B55707D6EA7B2","fee_type":"CNY","mch_id":"1491307962","cash_fee":"10","out_trade_no":"14913079622018052909183048768217","appid":"wxa177427bc0e60aab","total_fee":"10","trade_type":"JSAPI","result_code":"SUCCESS","time_end":"20180529091834","is_subscribe":"N","return_code":"SUCCESS"}
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getLocalIp() {
        InetAddress ia = null;
        String localIp = null;
        try {
            ia = ia.getLocalHost();
            localIp = ia.getHostAddress();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return localIp;
    }

}
